import path from 'path';
import fs from 'fs';
import webpack from 'webpack';
import HtmlWebpackPlugin from 'html-webpack-plugin';
import { execSync } from 'child_process';

/**
 * 处理构建完成的回调函数
 * 当 Webpack 构建完成后，检查是否有错误或统计信息，并输出相应日志。
 * 若存在错误，输出错误信息并终止进程；若统计信息不存在，输出错误日志。
 * 
 * @param {Error | null | undefined} err - 构建过程中出现的错误，如果没有则为 null 或 undefined
 * @param {webpack.Stats | undefined} stats - 构建的统计信息，如果没有则为 undefined
 */
export function handleBuildComplete(err: Error | null | undefined, stats: webpack.Stats | undefined) {
    if (err) {
        console.error('[BUILD ERROR]', err.stack || err);
        if ((err as any).details) {
            console.error('[DETAILS]', (err as any).details);
        }
        process.exit(1);
    }

    if (!stats) {
        console.error('No stats available');
        return;
    }

    const statsJson = stats.toJson({
        errors: true,
        warnings: true,
        timings: true
    });

    // 处理编译错误（watch模式下不退出）
    if (stats.hasErrors()) {
        console.error(`\n❌ 编译失败 (耗时: ${statsJson.time}ms)`);

        statsJson.errors!.forEach(error => {
            const msg = error.message;
            // 模块未找到的特殊处理
            const moduleNotFoundRegex = /Module not found: Error: Can't resolve '([^']+)' in '([^']+)'/;
            const match = msg.match(moduleNotFoundRegex);
            if (match) {
                console.log(`  ➥ 模块未找到: ${match[1]} (在 ${match[2]} 中)`)
            } else {
                console.error(`  ➥ ${error.message}`);
            }
        });
        return;
    }
    console.log(stats.toString({
        colors: true,
        modules: false,
        children: false,
        chunks: false,
        chunkModules: false
    }));
}

/**
 * 设置 miniui 资源
 * 根据 Webpack 配置，将 miniui 相关资源复制或创建符号链接到构建输出目录。
 * 在 Windows 系统下使用复制操作，其他系统使用符号链接。
 * 
 * @param {webpack.Configuration} config - Webpack 配置对象
 */
export function setupMiniUIResources(config: webpack.Configuration) {
    const distPath = path.join(config.output!.path!, 'common/miniui');
    if (!fs.existsSync(distPath)) {
        fs.mkdirSync(distPath, { recursive: true });
    }

    ['locale', 'themes', 'res'].forEach(dirName => {
        const source = path.join(config.context!, 'node_modules/miniui-components', dirName);
        const target = path.join(distPath, dirName);

        if (fs.existsSync(source) && !fs.existsSync(target)) {
            if (process.platform === 'win32') {
                fs.cpSync(source, target, { recursive: true });
            } else {
                fs.symlinkSync(source, target, 'dir');
            }
        }
    });
}
/**
 * 设置PHP资源
 * 优化版：仅在生产模式下编译PHP文件到字节码，并创建指向php_bytecode目录的符号链接
 * 在开发模式下保持原始做法，方便调试PHP代码
 * @param {webpack.Configuration} config - Webpack 配置对象
 */
export function setupPHPResources(config: webpack.Configuration) {
    const distPath = path.join(config.output!.path!, 'php');
    const phpSource = path.join(config.context!, '../php');
    const phpBytecode = path.join(config.context!, '../php_bytecode');
    
    // 确保字节码目录存在
    if (!fs.existsSync(phpBytecode)) {
        fs.mkdirSync(phpBytecode, { recursive: true });
    }
    
    // 编译PHP文件到字节码（仅在生产模式下）
    if (config.mode === 'production') {
        console.log('[PHP] 开始编译PHP文件到字节码...');
        const compileScript = path.join(phpSource, 'compile_php.php');
        if (fs.existsSync(compileScript)) {
            try {
                // 执行编译脚本，启用CLI模式下的OPcache
                execSync(`php -d opcache.enable_cli=1 ${compileScript}`, { stdio: 'inherit' });
                console.log('[PHP] PHP文件编译完成！');
                
                // 创建指向字节码目录的符号链接
                if (fs.existsSync(distPath)) {
                    // 删除已存在的链接或目录
                    if (fs.lstatSync(distPath).isSymbolicLink()) {
                        fs.unlinkSync(distPath);
                    } else if (fs.statSync(distPath).isDirectory()) {
                        fs.rmSync(distPath, { recursive: true });
                    }
                }
                
                if (process.platform === 'win32') {
                    // Windows下复制字节码文件
                    fs.cpSync(phpBytecode, distPath, { recursive: true });
                } else {
                    // Linux/Mac下创建符号链接
                    fs.symlinkSync(phpBytecode, distPath, "dir");
                }
                console.log('[PHP] 已创建指向字节码目录的链接');
            } catch (error) {
                console.error('[PHP] 编译PHP文件失败，回退到原代码:', error);
                // 回退到原始PHP文件
                setupOriginalPHPResources(config, distPath, phpSource);
            }
        } else {
            console.warn('[PHP] 编译脚本不存在，回退到原代码');
            setupOriginalPHPResources(config, distPath, phpSource);
        }
    } else {
        // 开发环境使用原始PHP文件
        setupOriginalPHPResources(config, distPath, phpSource);
    }
}

/**
 * 设置原始PHP资源（备用方法）
 * @param {webpack.Configuration} config - Webpack 配置对象
 * @param {string} distPath - 目标路径
 * @param {string} sourcePath - 源路径
 */
function setupOriginalPHPResources(config: webpack.Configuration, distPath: string, sourcePath: string) {
    if (fs.existsSync(sourcePath) && !fs.existsSync(distPath)) {
        if (process.platform === 'win32') {
            fs.cpSync(sourcePath, distPath, { recursive: true });
        } else {
            fs.symlinkSync(sourcePath, distPath, "dir");
        }
    }
}

/**
 * 解析命令行参数
 * 从 `process.argv` 中提取参数，判断是否包含 `--watch` 或 `-w` 选项，用于决定是否开启监听模式。
 * 
 * @returns {{ watch: boolean }} - 包含 `watch` 属性的对象，`watch` 为布尔值，表示是否开启监听模式
 */
export function parseArgs() {
    const args = process.argv.slice(2);
    return {
        watch: args.includes('--watch') || args.includes('-w')
    };
}

/**
 * 查找页面入口的辅助函数
 * 递归扫描指定目录下的 HTML 或 PHP 文件，为每个文件生成对应的页面信息和入口信息。
 * 若存在对应的 TS 文件，则将其作为入口添加到入口对象中。
 * 
 * @param {string} baseDir - 扫描的基础目录路径
 * @returns {{ pages: Array<{ template: string; filename: string; chunk: string }>; entries: Record<string, string> }} - 包含页面信息数组和入口对象的对象
 */
export function findPagesAndEntries(baseDir: string) {
    const pages: Array<{ template: string; filename: string; chunk: string }> = [];
    const entries: Record<string, string> = {};
    const login = path.join(baseDir, "common", "login.ts");
    if (fs.existsSync(login)) {
        entries["login"] = login;
    }
    function scan(dir: string) {
        const files = fs.readdirSync(dir);

        for (const file of files) {
            const fullPath = path.join(dir, file);
            const stat = fs.statSync(fullPath);

            if (stat.isDirectory()) {
                scan(fullPath);
            } else if (/\.(html|php)$/.test(file)) {
                const relativePath = path.relative(baseDir, fullPath);
                const dirname = path.dirname(relativePath);
                const basename = path.basename(file, path.extname(file));
                const chunk = dirname === '.' ? basename : `${dirname}/${basename}`;

                // 计算对应的 TS 文件路径
                const tsFile = path.join(
                    path.dirname(fullPath),
                    `${basename}.ts`
                );

                pages.push({
                    template: relativePath,
                    filename: relativePath,
                    chunk: chunk
                });

                if (fs.existsSync(tsFile)) {
                    entries[chunk] = `./${path.relative(baseDir, tsFile)}`;
                }
            }
        }
    }

    scan(baseDir);
    return { pages, entries };
}

/**
 * 创建 CSS 样式处理器
 * 返回一个函数，用于处理 CSS 中的背景图片引用，提取图片 URL 并记录相关信息。
 * 
 * @returns {(param: any, sources: any) => boolean} - 样式处理函数，返回一个布尔值，表示是否处理了背景图片引用
 */
export function createStyleHandler() {
    return function style(param: any, sources: any) {
        const regex = /url\(\s*["']?([^"')]+)["']?\s*\)/gi;
        let match;
        let processed = false;
        while ((match = regex.exec(param.value)) !== null) {
            const [fullMatch, url] = match;
            const offset = fullMatch.indexOf(url!) + match.index + param.startOffset;
            sources.push({
                name: 'url',
                value: url,
                isValueQuoted: false,
                startOffset: offset,
                endOffset: offset + url!.length
            });
            processed = true;
        }
        return processed;
    };
}

/**
 * 动态添加 entry 和 HtmlWebpackPlugin
 * 监控项目目录下的 HTML 或 PHP 文件变化，当文件新增时，动态更新 Webpack 的入口和 HTML 插件配置。
 * 使用防抖处理文件变化事件，避免频繁重新构建。
 * 
 * @param {webpack.Compiler} compiler - Webpack 编译器实例
 * @param {webpack.Watching} watcher - Webpack 监听实例
 */
export function setupDynamicEntry(compiler: webpack.Compiler, watcher: webpack.Watching) {
    const pendingEntries: Record<string, string> = {};
    const pendingHtmlPlugins: HtmlWebpackPlugin[] = [];
    let debounceTimer: NodeJS.Timeout;

    /**
     * 处理文件变化的内部函数
     * 根据文件变化类型（新增）更新待处理的入口和 HTML 插件列表，
     * 并通过防抖机制触发 Webpack 重新构建。
     * 
     * @param {string} filePath - 发生变化的文件的完整路径
     * @param {boolean} isRemoved - 指示文件是否被删除
     */
    const handleFileChange = (filePath: string, isRemoved: boolean) => {
        const relativePath = path.relative(compiler.context, filePath);
        const basename = path.basename(filePath, path.extname(filePath));
        const dirname = path.dirname(relativePath);
        const chunk = dirname === '.' ? basename : `${dirname.replace(/\//g, '_')}_${basename}`;

        if (!isRemoved) {
            // 处理新增的文件
            const tsFile = filePath.replace(/\.(html|php)$/, '.ts');

            if (!fs.existsSync(tsFile)) {
                fs.writeFileSync(tsFile, '// 自动生成的入口文件\nconsole.log("test");');
                console.log(`[自动创建] ${path.relative(compiler.context, tsFile)}`);
            }

            pendingEntries[chunk] = `./${path.relative(compiler.context, tsFile)}`;
            pendingHtmlPlugins.push(new HtmlWebpackPlugin({
                template: relativePath,
                filename: relativePath, // 保持与源文件相同的路径结构
                chunks: [chunk],
                inject: true,
                scriptLoading: "blocking"
            }));
        }

        // 防抖处理
        clearTimeout(debounceTimer);
        debounceTimer = setTimeout(() => {
            watcher.invalidate();
        }, 500);
    };

    // 设置文件监控
    fs.watch(compiler.context, { recursive: true }, (event, filename) => {
        if (filename && /\.(html|php)$/.test(filename)) {
            const fullPath = path.join(compiler.context, filename);
            if (event === 'rename') {
                // 判断是删除还是新增
                const isRemoved = !fs.existsSync(fullPath);
                handleFileChange(fullPath, isRemoved);
            }
        }
    });

    // 在编译前处理 entry 变更
    compiler.hooks.watchRun.tapAsync('DynamicEntryPlugin', (compilation, callback) => {
        // 处理新增 entry
        Object.entries(pendingEntries).forEach(([name, path]) => {
            new webpack.EntryPlugin(compiler.context, path, { name }).apply(compilation);
        });

        // 处理新增的 HtmlWebpackPlugin
        pendingHtmlPlugins.forEach(plugin => plugin.apply(compilation));

        // 清空待处理队列
        Object.keys(pendingEntries).forEach(key => delete pendingEntries[key]);
        pendingHtmlPlugins.length = 0;

        callback();
    });
}

